﻿package code {
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	import flash.geom.Point;
	import flash.events.TimerEvent;
	
	public class EnemyWave
	{
		// Reference to the enemy spawner
		private var spawner:EnemySpawner;
		// Dictionary of singular enemies within this wave
		private var enemies:Dictionary;
		// Vector of timers which spawn continuous enemies
		private var timers:Vector.<KeyValuePair>;
		// Identifies if this wave has been triggered (put in play)
		private var triggered:Boolean;
		// Identifies if this wave has been completed by the player
		private var completed:Boolean;
		// Number of singular enemies in play
		private var enemyCount:int;
		// Number of continuous-enemy timers
		private var timerCount:int;
		
		// Identifies if this wave has been triggered (put in play)
		public function get Triggered():Boolean { return triggered; }
		// Identifies if this wave has been completed by the player
		public function get Completed():Boolean { return completed; }
		// Number of singular enemies left in play
		public function get EnemiesLeft():int { return enemyCount; }

		public function EnemyWave(spawner:EnemySpawner)
		{
			this.spawner = spawner;
			enemies = new Dictionary(true);
			timers = new Vector.<KeyValuePair>();
			triggered = false;
			completed = false;
			enemyCount = 0;
			timerCount = 0;
		}
		
		// Adss a "singular" enemy into this wave
		// Singular enemies is a one-time-only spawned enemy
		public function addSingularEnemy(type:String, spawnX:String, spawnYNum:int)
		{
			var enemyAdding:GenericEnemy;
			var spawnXNum:int = 0;
			
			if (spawnX == "rand")
			{
				spawnXNum = Math.random() * 640;
			}
			else
			{
				spawnXNum = parseInt(spawnX);
			}
			
			switch(type)
			{
				case "sugarmine":
					enemyAdding = new SugarCubeMine(Level.ScrollFactor, spawnXNum, spawnYNum);
					break;
				
				case "candycorn":
					enemyAdding = new CandyCorn(Level.ScrollFactor, spawnXNum, spawnYNum);
					break;
				
				default:
					throw new Error("Enemy type'" + type + "' not found");
					break;
			}
			
			if (enemyAdding != null)
			{
				enemies[enemyAdding] = enemyAdding;
				enemyCount++;
			}
		}
		
		// Adds a "continuous" enemy into this wave
		// Continuous enemies are spanwed until a wave is completed at a specified timestep
		public function addContinuousEnemy(type:String, spawnX:int, spawnY:int, timestep:int)
		{
			trace("creating continuous '" + type + "' at every '" + timestep + 
				  "' interval at position '" + spawnX + ", " + spawnY + "'");
			
			timers[timers.length] = new KeyValuePair(new Timer(timestep), 
									new KeyValuePair(type, new Point(spawnX, spawnY)));
		}
		
		// Called when an enemy has been destroyed on the level, removes it from the wave
		public function removeEnemy(enemyRemoving:GenericEnemy)
		{
			for each(var enemy:GenericEnemy in enemies)
			{
				if (enemyRemoving == enemy)
				{
					trace("removed singular enemy");
					delete enemies[enemyRemoving];
					enemyCount--;
					
					break;
				}
			}
			
			if (enemyCount == 0)
			{
				completed = true;
				
				for each (var continuousEnemy:GenericEnemy in enemies)
				{
					delete enemies[continuousEnemy];
				}
				enemies = null;
				
				for each (var kv:KeyValuePair in timers)
				{
					(kv.Key as Timer).stop();
					(kv.Key as Timer).removeEventListener(TimerEvent.TIMER, timerTick);
					
					timers.splice(timers.indexOf(kv), 1);
				}
				timers = null;
			}
		}
		
		// Triggers the wave to be put into play
		public function trigger()
		{
			triggered = true;
			
			for each (var enemy:GenericEnemy in enemies)
			{
				spawner.CurrentLevel.addEnemy(enemy);
			}
			
			for each (var kv:KeyValuePair in timers)
			{
				(kv.Key as Timer).addEventListener(TimerEvent.TIMER, timerTick);
				(kv.Key as Timer).start();
			}
		}
		
		// Finds timer which completed, spawns an enemy associated with it and restarts timer
		public function timerTick(e:TimerEvent)
		{
			if (completed) return;
			
			for each (var kv:KeyValuePair in timers)
			{
				if (e.target == kv.Key)
				{
					trace("timer tick");
					var type:String = (kv.Value as KeyValuePair).Key as String;
					var spawnPos:Point = (kv.Value as KeyValuePair).Value as Point;
					
					switch (type)
					{
						case "sugarmine":
							spawner.CurrentLevel.addEnemy(new SugarCubeMine(Level.ScrollFactor, spawnPos.x, spawnPos.y));
							break;
						
						case "candycorn":
							spawner.CurrentLevel.addEnemy(new CandyCorn(Level.ScrollFactor, spawnPos.x, spawnPos.y));
							break;
					}
					
					break;
				}
			}
			
			(e.target as Timer).reset();
			(e.target as Timer).start();
		}

	}
}